package blazingbubble.gui.panels;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

import blazingbubble.game.Player;
import blazingbubble.game.command.GameCommandFactory;
import blazingbubble.graphics.game.IGamePlayerActivityListener;
import blazingbubble.graphics.game.IJoinGameListener;
import blazingbubble.gui.ISwitchable;
import blazingbubble.gui.PanelRegistry;
import blazingbubble.gui.Resources;
import blazingbubble.gui.elements.MenuButton;
import blazingbubble.gui.elements.MenuLabel;
import blazingbubble.gui.elements.MenuTable;
import blazingbubble.network.game.strategy.IPlayerTeamJoinListener;

public class GameLobbyPanel extends JPanel implements ActionListener, IPlayerTeamJoinListener, IJoinGameListener, IGamePlayerActivityListener {
	private static class Team extends JPanel {
		private static final long serialVersionUID = 7286788028304209125L;
		private boolean swapIndices;
		private DefaultTableModel players;
		private static final String[] playerColumnNames = {
		"Player"};

		public Team(String teamCaption, int teamSize, int index, GameCommandFactory commandFactory, boolean swapIndices) {
			this.swapIndices = swapIndices;
			players = new DefaultTableModel(null, playerColumnNames) {
				private static final long serialVersionUID = 7768569325667302218L;

				@Override
				public boolean isCellEditable(int row, int column) {
					return false;
				}
			};
			add(new MenuLabel(teamCaption, Font.BOLD, 12), BorderLayout.NORTH);
			MenuTable playerTable = new MenuTable(players, Font.PLAIN, 12);
			playerTable.getTableHeader().setBorder(BorderFactory.createEmptyBorder());
			JScrollPane scrollPane = new JScrollPane(playerTable);
			add(scrollPane, BorderLayout.CENTER);
			playerTable.addMouseListener(new ClickWatcher(playerTable, index, commandFactory, swapIndices));
			for(int i = 0; i < teamSize; i++) {
				players.insertRow(i, new Vector());
			}
			
		}

		public void playerTakeSlot(Player player) {
			players.removeRow(swapIndices ? player.getTeamIndex() : player.getPositionIndex());
			players.insertRow(swapIndices ? player.getTeamIndex() : player.getPositionIndex(), new Object[]{player.getName()});
		}

		public void playerTakeNextFreeSlot(Player player) {
			for(int i = 0; i < players.getRowCount(); i++) {
				if(players.getValueAt(i, 0) == null) {
					players.removeRow(i);
					players.insertRow(i, new Object[] { player.getName() });
					break;
				}
			}
		}

		public void removePlayerIfExists(Player player) {
			for(int i = 0; i < players.getRowCount(); i++) {
				if(player.getName().equals(players.getValueAt(i, 0))) {
					players.removeRow(i);
					players.insertRow(i, new Vector());
					break;
				}
			}
		}

		private class ClickWatcher extends MouseAdapter {
			private GameCommandFactory commandFactory;
			private JTable table;
			private int index;
			private boolean swapIndices;

			public ClickWatcher(JTable table, int index, GameCommandFactory commandFactory, boolean swapIndices) {
				this.commandFactory = commandFactory;
				this.swapIndices = swapIndices;
				this.table = table;
				this.index = index;
			}

			@Override
			public void mouseClicked(MouseEvent e) {
				int slot = table.rowAtPoint(e.getPoint());
				if(table.getModel().getValueAt(slot, 0) == null) {
					commandFactory.getJoinTeam().setTeamIndex(swapIndices ? slot : index);
					commandFactory.getJoinTeam().setSlotIndex(swapIndices ? index : slot);
					commandFactory.getJoinTeam().join();
				}
			}
		}
	}
	private static final long serialVersionUID = 7234786320043365025L;

	public static final String PANEL_NAME = "GameLobby";

	private static final Image BACKGROUND_IMAGE = Toolkit.getDefaultToolkit().createImage(Resources.BACKGROUND_NOTITLE_LARGE_IMAGEPATH);

	private ISwitchable parentFrame = null;

	private Team[] teams;
	private Team idlers;
	private boolean hasTeams;
	private GameCommandFactory commandFactory;

	private MenuButton startButton = new MenuButton(Resources.STARTGAMEBUTTON_IMAGEPATH);
	private MenuButton backButton = new MenuButton(Resources.BACKBUTTON_SMALL_IMAGEPATH);

	public GameLobbyPanel(ISwitchable parentFrame){
		this.commandFactory = parentFrame.getGameCommandFactory();
		this.parentFrame = parentFrame;
		PanelRegistry.getInstance().registerPanel(PANEL_NAME, this);
		setUp();
	}

	private void setUp(){
		this.setSize(500, 500);
		this.setLayout(null);

		this.add(backButton);
		backButton.addActionListener(this);
		backButton.setBounds(80, 415, 165, 55);

		this.add(startButton);
		startButton.addActionListener(this);
		startButton.setBounds(255, 415, 165, 55);
	}

	@Override
	public void paintComponent(Graphics g){  
		super.paintComponent(g);
		g.drawImage(BACKGROUND_IMAGE, 0, 0, getWidth(), getHeight(), this);  
	}

	@Override
	public void actionPerformed(ActionEvent event) {
		if (event.getSource().equals(backButton)){
			//TODO: leave game
		}
		else if (event.getSource().equals(startButton)){
			//TODO: start game
		}
	}

	@Override
	public void playerJoinedTeam(Player player) {
		removePlayer(player);
		if(player.getTeamIndex() == -1) {
			idlers.playerTakeNextFreeSlot(player);
		}
		else if(hasTeams) {
			teams[player.getTeamIndex()].playerTakeSlot(player);
		}
		else {
			teams[0].playerTakeSlot(player);
		}
	}

	@Override
	public void gameJoined(int teams, int teamSize) {
		preparePanel(teams, teamSize);
	}


	private void preparePanel(int teamCount, int teamSize) {
		if (teams!= null){
			for(int i = 0; i < teams.length; i++) {
				this.remove(teams[i]);
			}
		}

		if(teamSize == 1) {
			hasTeams = false;
			teams = new Team[1];
			teams[0] = new Team("Players", teamCount, 0, commandFactory, true);
			add(teams[0]);
			teams[0].setBounds(5, 5, 485, 380);
			//todo: set bounds
		}
		else {
			hasTeams = true;
			teams = new Team[teamCount];
			for(int i = 0; i < teams.length; i++) {
				teams[i] = new Team("Team " + (i + 1), teamSize, i, commandFactory, false);
				add(teams[i]);
				teams[i].setBounds(5, 5 + (i * 120), 485, 115);
			}
		}
		/*TODO: removed 
		 * parentFrame.switchSize(500, 500);
		 * parentFrame.switchPanel(this);
		 * from here
		*/
	}

	private void removePlayer(Player player) {
		if (idlers != null){
			idlers.removePlayerIfExists(player);
		}
		//if (teams != null){
			for(Team team : teams) {
				team.removePlayerIfExists(player);
			}
//		}
	}

	@Override
	public void playerJoined(Player player) {
		removePlayer(player);
		if(player.getTeamIndex() == -1) {
			idlers.playerTakeNextFreeSlot(player);
		}
		else if(hasTeams) {
			teams[player.getTeamIndex()].playerTakeSlot(player);
		}
		else {
			teams[0].playerTakeSlot(player);
		}
	}
}
